﻿Imports System.IO
Imports System.Text

Public Class EndianReader
    Inherits BinaryReader
    Private order As ByteOrder

    Public Sub New(inStream As Stream, bOrder As ByteOrder, tEncoding As Encoding)
        MyBase.New(inStream, tEncoding)
        order = bOrder
    End Sub

    Public Sub New(inStream As Stream, bOrder As ByteOrder)
        MyBase.New(inStream, Encoding.ASCII)
        order = bOrder
    End Sub

    Public Overrides Function ReadInt16() As Short
        Return EndianSwap.SwapToInt16(MyBase.ReadBytes(2), order)
    End Function

    Public Function ReadInt16Array(count As Integer) As Short()
        Dim temp(count - 1) As Short
        For i As Integer = 0 To count - 1
            temp(i) = EndianSwap.SwapToInt16(MyBase.ReadBytes(2), order)
        Next
        Return temp
    End Function

    Public Overrides Function ReadInt32() As Integer
        Return EndianSwap.SwapToInt32(MyBase.ReadBytes(4), order)
    End Function

    Public Function ReadInt32Array(count As Integer) As Integer()
        Dim temp(count - 1) As Integer
        For i As Integer = 0 To count - 1
            temp(i) = EndianSwap.SwapToInt32(MyBase.ReadBytes(4), order)
        Next
        Return temp
    End Function

    Public Overrides Function ReadInt64() As Long
        Return EndianSwap.SwapToInt64(MyBase.ReadBytes(8), order)
    End Function

    Public Overrides Function ReadUInt16() As UShort
        Return BitConverter.ToUInt16(ByteSwap(BitConverter.GetBytes(MyBase.ReadUInt16())), 0)
    End Function

    Public Overrides Function ReadUInt32() As UInteger
        Return BitConverter.ToUInt32(ByteSwap(BitConverter.GetBytes(MyBase.ReadUInt32())), 0)
    End Function

    Public Overrides Function ReadUInt64() As ULong
        Return BitConverter.ToUInt64(ByteSwap(BitConverter.GetBytes(MyBase.ReadUInt64())), 0)
    End Function

    Public Overrides Function ReadSingle() As Single
        Return EndianSwap.SwapToSingle(MyBase.ReadBytes(4), order)
        'return BitConverter.ToSingle(ByteSwap(BitConverter.GetBytes(base.ReadSingle())), 0);
    End Function
    Public Function ReadSingleArray(count As Integer) As Single()
        Dim temp As Single() = New Single(count - 1) {}
        For i As Integer = 0 To count - 1
            'BitConverter.ToSingle(ByteSwap(BitConverter.GetBytes(base.ReadSingle())), 0);
            temp(i) = EndianSwap.SwapToSingle(MyBase.ReadBytes(4), order)
        Next
        Return temp
    End Function
    Public Overrides Function ReadDouble() As Double
        Return BitConverter.ToDouble(ByteSwap(BitConverter.GetBytes(MyBase.ReadDouble())), 0)
    End Function

    Public Function ReadFourCC() As String
        Dim fourcc As String = ReadString(4)
        If order = ByteOrder.LittleEndian Then
            Return EndianSwap.ReverseString(fourcc)
        Else
            Return fourcc
        End If
    End Function

    Public Property Position() As Integer
        Get
            Return CInt(MyBase.BaseStream.Position)
        End Get
        Set
            MyBase.BaseStream.Position = Value
        End Set
    End Property

    Public Property Length() As Integer
        Get
            Return CInt(MyBase.BaseStream.Length)
        End Get
        Set
            MyBase.BaseStream.SetLength(Value)
        End Set
    End Property

    Public Overloads Function ReadString(len As Integer) As String
        Return System.Text.ASCIIEncoding.ASCII.GetString(MyBase.ReadBytes(len))
    End Function
    Public Overloads Function ReadString(len As Integer, Optional nullend As Boolean = False) As String
        Dim ret As String = System.Text.ASCIIEncoding.ASCII.GetString(MyBase.ReadBytes(len))
        If nullend Then
            MyBase.ReadByte()
        End If
        Return ret
    End Function

    Public Overrides Function ReadString() As String
        Dim chr As Char = ControlChars.NullChar
        Dim str As String = ""
        Do
            chr = Convert.ToChar(MyBase.ReadByte())
            str += chr
        Loop While chr <> ControlChars.NullChar
        Return str.Substring(0, str.Length - 1)
    End Function


    Protected Function ByteSwap(bytes As Byte()) As Byte()
        If order = ByteOrder.BigEndian Then
            Select Case bytes.Length
                Case 2, 4, 8
                    EndianSwap.ByteSwap(bytes)
                    Exit Select
                Case Else
                    Throw New NotSupportedException("Stream lengths other than 2, 4, and 8 are invalid for an endian swap.")
            End Select
        End If
        Return bytes
    End Function
End Class